/* Copyright (c) 2010, Peter Lényi */
/* Licensed under The BSD License. */

package gem.apps.fs.db;

import gem.apps.fs.entities.FileMeta;
import java.util.List;
import javax.persistence.Query;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;

/**
 * Manager class DatabaseManagerImpl provides an implementation of the DatabaseManager
 * interface.
 * <p/>
 * This is an implementation for the Embedded Derby Database; there is a hack that
 * makes this class work - if the database already exists and application attempts
 * to recreate it, an exception is thrown and immediately caught and different
 * Persistence Unit is used (one that does not try to create the database). This
 * exception may still occur in the server logs.
 * 
 * @author Peter Lényi
 * @version 20100426F
 */
public final class DatabaseManagerImpl implements DatabaseManager
{
    private static DatabaseManager instance = null;

    private EntityManagerFactory emf = Persistence.createEntityManagerFactory("GFSPU_SQLite");

    /**
     * @return class instance.
     */
    public static DatabaseManager getInstance() {
        if (instance == null) {
            instance = new DatabaseManagerImpl();
        }
        return instance;
    }

    private DatabaseManagerImpl() { /* SINGLETON, FACTORY METHOD PATTERNS */ }

    @SuppressWarnings("unchecked")
    public List<FileMeta> listFileMeta() throws DatabaseCallException {
        EntityManager em = emf.createEntityManager();
        Query querySelectAll = em.createNativeQuery("SELECT * FROM filemeta ORDER BY title ASC", FileMeta.class);
        List<FileMeta> fileMetas = null;
        try {
            em.getTransaction().begin();
            fileMetas = querySelectAll.getResultList();
            em.getTransaction().commit();
        }
        catch (PersistenceException ex) {
            em.getTransaction().rollback();
            throw new DatabaseCallException("Could not list file meta.", ex);
        }
        finally {
            em.close();
        }
        return fileMetas;
    }
    
    public List<FileMeta> listFileMeta(int pageSize, int pageNumber) throws DatabaseCallException {
        EntityManager em = emf.createEntityManager();
        Query querySelectAll = em.createNativeQuery("SELECT * FROM filemeta ORDER BY title ASC LIMIT :limit OFFSET :offset ", FileMeta.class);
        querySelectAll.setParameter(":limit", pageSize);
        querySelectAll.setParameter(":offset", pageSize * (pageNumber - 1));
        List<FileMeta> fileMetas = null;
        try {
            em.getTransaction().begin();
            fileMetas = querySelectAll.getResultList();
            em.getTransaction().commit();
        }
        catch (PersistenceException ex) {
            em.getTransaction().rollback();
            throw new DatabaseCallException("Could not list file meta.", ex);
        }
        finally {
            em.close();
        }
        return fileMetas;
    }

    public void insertFileMeta(FileMeta meta) throws DatabaseCallException {
        EntityManager em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            em.persist(meta);
            em.getTransaction().commit();
        }
        catch (PersistenceException ex) {
            em.getTransaction().rollback();
            throw new DatabaseCallException("Could not insert file meta.", ex);
        }
        finally {
            em.close();
        }
    }

    public FileMeta selectFileMeta(FileMeta meta) throws DatabaseCallException {
        EntityManager em = emf.createEntityManager();
        FileMeta newMeta = null;
        try {
            em.getTransaction().begin();
            newMeta = em.find(FileMeta.class, meta.getUin());
            em.getTransaction().commit();
        }
        catch (PersistenceException ex) {
            em.getTransaction().rollback();
            throw new DatabaseCallException("Could not select file meta.", ex);
        }
        finally {
            em.close();
        }
        return newMeta;
    }

    public void updateFileMeta(FileMeta meta) throws DatabaseCallException {
        EntityManager em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            FileMeta oldMeta = em.find(FileMeta.class, meta.getUin());
            oldMeta.setTitle(meta.getTitle());
            oldMeta.setComment(meta.getComment());
            oldMeta.setPassword(meta.getPassword());
            oldMeta.setMime(meta.getMime());
            em.getTransaction().commit();
        }
        catch (PersistenceException ex) {
            em.getTransaction().rollback();
            throw new DatabaseCallException("Could not update file meta.", ex);
        }
        finally {
            em.close();
        }
    }

    public void deleteFileMeta(FileMeta meta) throws DatabaseCallException {
        EntityManager em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            FileMeta rmeta = em.find(FileMeta.class, meta.getUin());
            em.remove(rmeta);
            em.getTransaction().commit();
        }
        catch (PersistenceException ex) {
            em.getTransaction().rollback();
            throw new DatabaseCallException("Could not update file meta.", ex);
        }
        finally {
            em.close();
        }
    }
}
